using System;

namespace Atomic.Libraries.Mathematics.RandomNumbers
{
	[Serializable]
	public class PolarBoxMullerGenerator : IGaussianGenerator
	{
		private IRandomGenerator baseGenerator;
		private double nextValue;
		private bool hasNext;

		public PolarBoxMullerGenerator(IRandomGenerator baseGenerator)
		{
			this.baseGenerator = baseGenerator;
		}

		public double NextSample()
		{
			if (hasNext)
			{
				hasNext = false;
				return nextValue;
			}
			else
			{
				double x, y, w;

				do
				{
					x = 2.0 * baseGenerator.NextDouble() - 1.0;
					y = 2.0 * baseGenerator.NextDouble() - 1.0;
					w = x * x + y * y;
				} while (w >= 1.0 || w == 0.0);

				w = Math.Sqrt(-2.0 * Math.Log(w) / w);

				x *= w;
				y *= w;

				nextValue = y;
				hasNext = true;
				
				return x;
			}
		}
	}
}
